#ifndef HASHTABLE_H
#define HASHTABLE_H

#define DEFAULT_LOAD_FACTOR         0.75
#define DEFAULT_HASH_TABLE_CAPACITY 4

typedef struct Entry {
    void         *key;
    void         *value;
    struct Entry *next;
} Entry;

typedef struct {
    float   loadFactor;
    int     threshold;
    int     capacity;
    int     size;
    Entry **table;
    int     (*keyCompare)(const void *key1, const void *key2);
    int     (*keyHash)(const void *key);
    void    (*keyDestroy)(void *key);
    void    (*valueDestroy)(void *value);
    void   *(*valueDup)(void *value);
} HashTable;

HashTable *hash_table_create();
void       hash_table_destroy(HashTable *hash_table);
Entry     *hash_table_create_entry(void *key, void *value);
void       hash_table_entry_destroy(HashTable *hash_table, Entry *entry);
void       hash_table_entry_reset(Entry *entry);
void       hash_table_put(HashTable *hash_table, void *key, void *value);
int        hash_table_have(HashTable *hash_table, void *key);
void      *hash_table_get(HashTable *hash_table, void *key);
void       hash_table_full_remove(HashTable *hash_table, void *key);
void       hash_table_remove(HashTable *hash_table, void *key);
void      *hash_table_pop(HashTable *hash_table, void *key);
void       hash_table_resize(HashTable *hash_table);
int        hash_table_get_size(HashTable *hash_table);
int        hash_table_default_key_compare(const void *key1, const void *key2);
int        hash_table_default_key_hash(const void *key);
void       hash_table_default_key_destroy(void *key);
void       hash_table_default_value_destroy(void *value);
void      *hash_table_default_value_dup(void *value);

#endif // HASHTABLE_H
